package main

import (
	"fmt"
	"sync"
	"time"
)

// 并发编程 锁
func demo14() {
	//demo14_group()
	//demo14_map()
	//demo14_pool()
	demo14_cond()
}

func demo14_cond() {
	c := sync.NewCond(new(sync.Mutex))
	flag := true
	go func() {
		c.L.Lock()
		fmt.Println("lock1")
		for flag {
			c.Wait()
		}
		fmt.Println("unlock1")
		c.L.Unlock()
	}()
	go func() {
		c.L.Lock()
		fmt.Println("lock2")
		for flag {
			c.Wait()
		}
		fmt.Println("unlock2")
		c.L.Unlock()
	}()
	time.Sleep(time.Second * 1)
	flag = false
	c.Signal()
	time.Sleep(time.Second * 1)
	c.Signal()
	time.Sleep(time.Second * 1)
	fmt.Println("all cond")
	// c.Broadcast() 广播 唤醒所有等待的
}

// 并发池
func demo14_pool() {
	p := &sync.Pool{}
	p.Put(1)
	p.Put(2)
	p.Put(3)
	p.Put(4)
	p.Put(5)
	p.Put(6)

	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		fmt.Println(p.Get())
	}
}

func demo14_map() {
	/*
		// 报错 不允许同时读和写 使用 sync.Map可以解决
		m := make(map[int]int)
		go func() {
			for {
				m[1] = 1
				fmt.Println("hp +1")
			}
		}()
		go func() {
			for {
				fmt.Println("hp ", m[1])
			}
		}()
		time.Sleep(time.Second * 10)
	*/

	m := &sync.Map{}
	m.Store(1, 1)
	m.Store(2, 2)       // 存在则覆盖
	m.LoadOrStore(3, 3) // 不存在则设置
	m.Delete(1)         // 删除
	m.Range(func(key, value interface{}) bool {
		fmt.Println("hp ", key, value)
		time.Sleep(time.Second * 1)
		return true
	})
	/*
		go func() {
			for {
				m.Store(1, 1)
				fmt.Println("hp +1")
			}
		}()
		go func() {
			for {
				v, err := m.Load(1)
				fmt.Printf("hp %d %s", v, err)
			}
		}()
	*/
	time.Sleep(time.Second * 1)
}

// sync.WaitGroup
func demo14_group() {
	with := &sync.WaitGroup{}
	with.Add(2) // 表示2次才结束进程
	go func() {
		time.Sleep(time.Second * 6)
		fmt.Println("hp -1")
		with.Done()
	}()

	go func() {
		time.Sleep(time.Second * 8)
		fmt.Println("hp -1")
		with.Done()
	}()
	with.Wait()
	// 此时 阻塞时间为5秒 打印不到信息 可以使用 sync.WaitGroup 解决
	//time.Sleep(time.Second * 5)
	fmt.Println("game over")
}

func demo14_do() {
	o := &sync.Once{}
	for i := 0; i < 10; i++ {
		o.Do(func() {
			fmt.Println("只执行一次")
		})
	}
	for i := 0; i < 10; i++ {
		o.Do(func() {
			fmt.Println("只执行一次")
		})
	}
	for i := 0; i < 10; i++ {
		o.Do(func() {
			fmt.Println("只执行一次")
		})
	}
	for i := 0; i < 10; i++ {
		o.Do(func() {
			fmt.Println("只执行一次")
		})
	}
}

func demo14_1() {
	//// 没加锁的操作
	//go noLookFun()
	//go noLookFun()
	//go noLookFun()
	//go noLookFun()

	// l := new(sync.Mutex) 也可这样说明
	/*
		l := &sync.Mutex{} // 互斥锁
		l.Lock() // 互斥
	*/

	l := new(sync.RWMutex) // 读写锁
	// 写完后才能读
	// 读的时候排斥写锁 确保读取完后才能写

	// 加了锁后 变成原子操作
	go lookFun(l)
	go lookFun(l)
	go rwlookFun(l)
	go rwlookFun(l)
	go lookFun(l)
	go rwlookFun(l)
	go rwlookFun(l)
	//go lookFun(l)
	time.Sleep(time.Second * 10)
}

func lookFun(l *sync.RWMutex) {
	// 互斥锁 排斥 写 和 读的锁
	l.Lock()
	fmt.Println("刮痧")
	time.Sleep(time.Second)
	l.Unlock()
}
func rwlookFun(l *sync.RWMutex) {
	// 读锁 排斥写锁 不会排斥其他锁
	l.RLock()
	fmt.Println("治疗")
	time.Sleep(time.Second)
	l.RUnlock()
}

func noLookFun() {
	fmt.Println("nolook刮痧")
	time.Sleep(time.Second)
}
